package com.zy.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author zhy
 * @date 2025/6/19 17:18
 */
@Slf4j
public class EncryptUtil {
    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/ECB/PKCS5Padding";
    private static final String SECRET_KEY = "kmCLh9mxdfdEuXRLjp3hkw==";
    private static final String ENCRY_REPLACE = "ENCRY(%s)";
    private static final String ENCRY_PATTERN = "ENCRY\\((.*)\\)";
    private static final Cipher encryptedCipher;
    private static final Cipher decryptedCipher;
    private static final Pattern pattern;

    static {
        byte[] keyBytes = Base64.getDecoder().decode(SECRET_KEY);
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, ALGORITHM);
        try {
            encryptedCipher = genarateCipher(keySpec, Cipher.ENCRYPT_MODE);
            decryptedCipher = genarateCipher(keySpec, Cipher.DECRYPT_MODE);
        } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
            throw new RuntimeException(e);
        }
        pattern = Pattern.compile(ENCRY_PATTERN);
    }

    private static Cipher genarateCipher(SecretKeySpec keySpec, int mode) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException {
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(mode, keySpec);
        return cipher;
    }

    /**
     * 加密
     * @param plaintext 明文
     * @return
     */
    public static String encrypt(String plaintext) {
        if (StringUtils.isEmpty(plaintext)) {
            return "";
        }
        // 如果包含加密标识，则为加密数据，直接返回
        // 如果不包含加密标识，则为非加密数据，需要加密
        Matcher matcher = encryptMatcher(plaintext);
        if (matcher.find()) {
            return plaintext;
        }
        byte[] encryptedBytes;
        try {
            encryptedBytes = encryptedCipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        } catch (IllegalBlockSizeException | BadPaddingException e) {
            log.error(e.getMessage(), e);
            return "";
        }
        String encodeToString = Base64.getEncoder().encodeToString(encryptedBytes);
        return String.format(ENCRY_REPLACE, encodeToString);
    }

    /**
     * 解密
     * @param ciphertext 密文
     * @return
     */
    public static String decrypt(String ciphertext) {
        if (StringUtils.isEmpty(ciphertext)) {
            return "";
        }
        // 如果包含加密标识，则为加密数据，需要解密
        // 如果不包含加密标识，则为非加密数据，直接返回
        Matcher matcher = encryptMatcher(ciphertext);
        if (!matcher.find()) {
            return ciphertext;
        }
        if (matcher.groupCount() < 1) {
            return ciphertext;
        }
        ciphertext = matcher.group(1);
        byte[] decodedBytes = Base64.getDecoder().decode(ciphertext);
        byte[] decryptedBytes;
        try {
            decryptedBytes = decryptedCipher.doFinal(decodedBytes);
        } catch (IllegalBlockSizeException | BadPaddingException e) {
            log.error(e.getMessage(), e);
            return "";
        }
        return new String(decryptedBytes, StandardCharsets.UTF_8);
    }

    /**
     * 如果不包含加密标识，则加密
     * 如果包含加密标识，则解密
     * @param input
     * @return
     */
    public static String doEncrypt(String input) {
        if (StringUtils.isEmpty(input)) {
            return "";
        }
        Matcher matcher = encryptMatcher(input);
        if (matcher.find()) {
            return EncryptUtil.decrypt(input);
        } else {
            return EncryptUtil.encrypt(input);
        }
    }

    public static Matcher encryptMatcher(String input){
        return pattern.matcher(input);
    }
}
